
import os
import random
import time

import daysimfunc
from pybim import Building, Roof, Shade, Wall, Window, Zone


#THE CLASS WAS WRITTEN ASSUMING ALL THE POINTS ARE COMING IN ANTI-CLOCKWISE ARRANGEMENT WITH NORMAL POINTING OUTWARDS

ROOT = "/home/dexen/workspace/overhang_schema"


#==================================================

def geometry_info(variables, building):
    #CREATE THE BUILDING AND ZONE OBJECT
    zone1 = Zone("zone1", building)
    
    building_width = 15
    building_length = 15
    height = variables[4]
    num_wall = 4
    roof_list = [(building_length, building_width, height), (0, building_width, height), 
            (0, 0, height), (building_length, 0, height)]
    #ROOF CLASS
    roof = Roof("ROOF", roof_list)
    roof.material_idf("Heavy Roof/Ceiling")
    roof.material_rad("ceiling_mat")
    zone1.add_roof(roof)
    #in order of east west north south         
    wall_list = [[(building_length, 0, height), (building_length, 0, 0), (building_length, building_width, 0), 
                    (building_length, building_width, height)], 
                    
                    [(0, building_width, height), (0, building_width, 0), (0, 0, 0), (0, 0, height)], 
                    
                    [(building_length, building_width, height), (building_length, building_width, 0), 
                    (0, building_width, 0), (0, building_width, height)], 
                    
                    [(0, 0, height), (0, 0, 0), (building_length, 0, 0), (building_length, 0, height)]]
    
    wall_names = ["EASTWALL", "WESTWALL", "NORTHWALL", "SOUTHWALL"]
    
    #GET THE WINDOWS POINTS
    for counter in range(num_wall):
        #WALL CLASS
        wall = Wall(wall_names[counter], wall_list[counter])
        wall.material_idf("Medium Exterior Wall")
        wall.material_rad("wall_mat")
        zone1.add_wall(wall)
        
        width = variables[counter + 5]
        if width > 0 :
            win_top = height - 0.5 
            para_length = (float(building_length) - float(width)) / 2
            para_width = (float(building_width) - float(width)) / 2
            #in order of east west north south
            window_list = [[(building_length, para_width,  win_top), (building_length, para_width, 1),  (building_length, building_width-para_width,1 ), 
                    (building_length,  building_width-para_width,  win_top)], 
                    
                    [(0, building_width-para_width,  win_top), (0, building_width-para_width, 1),  (0, para_width,1 ), (0, para_width,  win_top)],
                    
                   [(building_length-para_length, building_width, win_top), (building_length-para_length,  building_width,  1),  
                   (para_length,  building_width,  1),  (para_length,  building_width, win_top)],  
                   
                   [(para_length, 0, win_top),  (para_length, 0, 1),  (building_length-para_length, 0, 1),  (building_length-para_length, 0, win_top)]]
            
            win_names = ["EASTWINDOW", "WESTWINDOW",  "NORTHWINDOW",  "SOUTHWINDOW"]
            
            window = Window(win_names[counter], window_list[counter])
            window.material_idf("Sgl Clr 6mm")
            window.material_rad("window_glass")
            wall.add_window(window)
            
    #GET THE SHADES POINTS
            depth = variables[counter]
            if depth > 0:
            #in order of east west north south
                shade_list = [[(building_length+depth, building_width-para_width, win_top), (building_length, building_width-para_width, win_top), 
                        (building_length, para_width, win_top), (building_length+depth, para_width, win_top)], 
                        
                        [(0, building_width-para_width, win_top),  (0-depth, building_width-para_width, win_top), 
                        (0-depth, para_width, win_top), (0, para_width, win_top)],
                        
                        [(para_length, building_width+depth, win_top), (para_length, building_width, win_top), 
                        (building_length-para_length, building_width, win_top), (building_length-para_length, building_width+depth, win_top)],   
                     
                        [(building_length-para_length, 0-depth, win_top), (building_length-para_length, 0, win_top), 
                        (para_length, 0, win_top), (para_length, 0-depth, win_top)]]
                shading_names  = ["EASTSHADING", "WESTSHADING",  "NORTHSHADING",  "SOUTHSHADING"]

                shade = Shade(shading_names[counter], shade_list[counter])
                shade.material_rad("shading_mat")
                wall.add_shade(shade)

#--------------------------------------------------------------------------------
#function for generating random height and width
def gmap(gene, values):
    step = 1.0 / len(values)
    for i in range(len(values)):
        if gene < (step + i*step):
            return values[i]
            
#--------------------------------------------------------------------------------
def generate_rad_file(variables, building):
    rad_data = []
    #WRITING THE RADIANCE FILE 
    #get the base file of the idf 
    base_rad_file = ROOT + '/radiancebasefile/overhangschema.rad'    

    #read all the stuff in the base idf file 
    base_rad_file = open(base_rad_file,  "r")
    base_rad_stuff = base_rad_file.read()
    base_rad_file.close()

    #write the base file 
    rad_data.append(base_rad_stuff)
    rad_geometry_data = building.rad(interior = True)
    rad_data.append(rad_geometry_data)
    return rad_data
    
#--------------------------------------------------------------------------------  
def generate_idf_file(variables, building):
             
    idf_data = []
    
    #WRITING THE ENERGYPLUS FILE 
    #get the base file of the idf 
    base_idf_file = ROOT + '/energyplusbasefile/overhangschema.idf'
    #read all the stuff in the base idf file 
    base_idf_file = open(base_idf_file,  "r")
    base_stuff = base_idf_file.read()
    base_idf_file.close()

    #write the base_stuff 
    idf_data.append(base_stuff)
    for _ in range(10):
        idf_data.append("! ======================================== \n")
        
    geometry_data = building.idf()
    idf_data.append(geometry_data)
    return idf_data
    
def execute_energyplus(idf_data,  path,  filename):
    
    idf_file_path = path + filename + ".idf"
    if not os.path.isdir(path):
        os.mkdir(path)
    idf_file = open(idf_file_path,  "w")
    for data in idf_data:
        idf_file.write(data)
    idf_file.close()
    
    #run energyplus simulation for each file 
    command = "runenergyplus '" +  idf_file_path + "' 'SGP_Singapore.486980_IWEC.epw'"
    os.system(command)
    
#--------------------------------------------------------------------------------
def generate_hea_file(path, filename, rad_file_path):
    
    #WRITING THE DAYSIM FILE 
    #get the base file of the hea
    base_hea_file = ROOT + '/daysimbasefile/overhangschema.hea'

    #read all the stuff in the base hea file 
    base_hea_file = open(base_hea_file,  "r")
    base_stuff = base_hea_file.read()
    base_hea_file.close()
    hea_data = []
    #create a foler to store daysim results / input the path as accordingly
    hea_data.append(base_stuff)
           
    #WRITE THE PROJ_INFO
    hea_file_path = path 
    tmp_dir = hea_file_path  + "tmp/"
    proj_info = daysimfunc.write_proj_info(filename, hea_file_path, tmp_dir)
    hea_data.append(proj_info)
    
    #WRITE THE WEATHER DATA 
    wea_file_dir = '/home/dexen/daysim/wea/SGP_Singapore.486980_IWEC_60min.wea' # in order to change the weather file input the 60min .wea dir, do the conversion from epw to wea using execute_epw2wea(bin_dir, source_file, destination_file)
    short_wea_name = "SGP_Singapore.486980_IWEC_5min.wea" # change the output .wea name respectively 
    weather_data = daysimfunc.write_weather_data(wea_file_dir, 0.2, short_wea_name)
    hea_data.append(weather_data)
    
    #WRITE THE GEOMETRY INFO

    sensor_file_dir = ROOT + '/radiancebasefile/ovrhg_sensor_pt.pts'
    rad_file_dir_list = [ROOT + "/radiancebasefile/overhangschema_mat.rad", 
                         ROOT + "/radiancebasefile/overhangschema.rad",
                         rad_file_path]
    geometry_data = daysimfunc.write_geometry_info(filename, sensor_file_dir, rad_file_dir_list)
    hea_data.append(geometry_data)
    
    #WRITE THE RESULTS INFO
    result_data = daysimfunc.write_result_file(filename)
    hea_data.append(result_data)
    
    return hea_data
#------------------------------------------------------------------------------    
def create_rad_file(rad_data, path, filename):
    rad_file_path = path + filename + ".rad"
    if not os.path.isdir(path):
        os.mkdir(path)
    rad_file = open(rad_file_path,  "w")
    for data in rad_data:
        rad_file.write(data)
    rad_file.close()
    return rad_file_path
#---------------------------------------------------------------------------------
def execute_daysim(hea_data, path, filename, bin_dir ):
    #create hea file           
    hea_file_path = path + filename + ".hea"
    if not os.path.isdir(path):
        os.mkdir(path)
    hea_file = open(hea_file_path,  "w")
    for data in hea_data:
        hea_file.write(data)
    hea_file.close()
    #within the folder create 5 folder :pts rad res tmp wea 
    sub_hea_folders = ["pts", "rad", "res","tmp", "wea"]
    for folder in range(len(sub_hea_folders)):
        sub_hea_folder = sub_hea_folders[folder]
        sub_hea_folders_path = path + sub_hea_folder
        
        if not os.path.isdir(sub_hea_folders_path):
            os.mkdir(sub_hea_folders_path)
        if os.path.isdir(sub_hea_folders_path):
            files_in_dir = os.listdir(sub_hea_folders_path)
            for file in files_in_dir:
                os.remove(sub_hea_folders_path + "/" + file )
    
    os.chdir(bin_dir)
    command1 = "ds_shortterm " +  "'" + hea_file_path +"'"
    os.system(command1)
    command2 = "radfiles2daysim " +  "'" + hea_file_path +"'" + " -g -m -d"
    os.system(command2)
    command3 = "gen_dc " +  "'" + hea_file_path +"'"
    os.system(command3)
    command4 = "ds_illum " +  "'" + hea_file_path +"'" 
    os.system(command4)
    command5 = "gen_directsunlight " +  "'" + hea_file_path +"'" 
    os.system(command5)
    command6 = "ds_autonomy " +  "'" + hea_file_path +"'" 
    os.system(command6)
    
#---------------------------------------------------------------------------------
def random_genotype(size):
    genotype = []
    for _ in range(size):
        genotype.append(random.random())
    return genotype
#--------------------------------------------------------------------------------
def map_genotype(genotype):
    # 1st to 4th genes are shade lengths between 0 and 2
    # 5th gene is the height
    # 6th to 9th genes are window widths (0 to 15)
    building_heights = [2.5, 3, 3.5, 4, 4.5, 5]
    window_widths = range(0, 16)
    variables = []
    for i in range(0, 4):
        variables.append(round ((genotype[i]* 2), 1))
    variables.append(gmap(genotype[4] ,  building_heights))
    for i in range(5, 9):
        variables.append(gmap(genotype[i] , window_widths ))
    return variables
#--------------------------------------------------------------------------------
def process_da_result(path, filename):
    da_results = open(path + "res/" + filename  + ".da", "r")
    da_result_stuff = da_results.readlines()
    
    num_da_list = []
    
    #daysim results processing average the DA
    for line in range(len(da_result_stuff)-2): 
        lines =  da_result_stuff[2+line][78:83] 
        numbers_da = float(lines)
        num_da_list.append(round(numbers_da, 1))
    avg_da = sum(num_da_list) / len(num_da_list)
    avg_da = round(avg_da, 1)
    return avg_da
    
def process_energy_results(path,  filename):
    
    #energyplus results processing average the energytransfer 
    energy_results = open(path + "Output/"  + filename + "Meter.csv", "r")
    energy_list = []
    energy_results.next()
    for energy_result in energy_results:
        words = energy_result.split (",")
        numbers = map(float, words[1:])
        energy_list.append(numbers)
    total = (sum(energy_list[0]) + sum(energy_list[1])) / 22
    total = total * 2.77777777777778E-07 # convert from J to KWh
    return total
    

def write_results(results):
    result_filepath = ROOT + "/result/"
    if not os.path.isdir(result_filepath):
        os.mkdir(result_filepath)
    result_file = open( result_filepath  + "finalresult.csv",  "w")
    #write the results into a csv file 
    result_file.write("project_name,daylight_autonomy(%),total_energy_transfer(kWh)(daily_avg)\n")
    result_file.write(results)
    result_file.close()

def develop(genotype):
    variables = map_genotype(genotype)
    building = Building()
    _ = geometry_info(variables, building)
    rad_file = generate_rad_file(variables, building)
    idf_file = generate_idf_file(variables, building)
    return rad_file,  idf_file
    
def eval_energy(idf_data):
    path = ROOT + "/energyplusbasefile/ep_out/"
    filename  = "results"
    execute_energyplus(idf_data,  path,  filename)
    result = process_energy_results(path,  filename)
    return result
    
def eval_daylight(rad_data):
    path = ROOT + "/daysimbasefile/daysim_out/"
    filename  = "da_results"
    bin_dir = "/home/dexen/daysim/bin"
    rad_path = ROOT + "/radiancebasefile/rad_out/"
    rad_filename  = "rad_results"
    rad = create_rad_file(rad_data, rad_path, rad_filename)
    hea_file = generate_hea_file(path, filename, rad)
    execute_daysim(hea_file, path, filename, bin_dir)
    result = process_da_result(path, filename)
    return result 

#--------------------------------------------------------------------------------
# MAIN SCRIPT
#--------------------------------------------------------------------------------
def main():
    random.seed()
    #CONVERT EPW TO WEA
    #setup()
    
    num_of_design = 1
    results = ""
    for counter in range(num_of_design):
        #generate the variables for the developmental script
        genotype = random_genotype(9)
        #developmental script
        rad_idf_data = develop(genotype)
        #evaluation
        st_time = time.time()
        daylight = eval_daylight(rad_idf_data[0])
        print "Daylight EXECUTION: ", time.time() - st_time
        energy = eval_energy(rad_idf_data[1])
        results = results + str(counter) + ","+ str(daylight) + "," +  str(energy) +"\n" 
        print "done"
        
    #write the results into a csv file 
    write_results(results)
    print "FINISH "

if __name__ == "__main__":
    main()





